package twilight.companion.entity;

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;

public class RotatingSnowBlockEntity extends Entity {
    private static final EntityDataAccessor<Float> ROTATION_SPEED = SynchedEntityData.defineId(RotatingSnowBlockEntity.class, 
            EntityDataSerializers.FLOAT);
            
    private static final EntityDataAccessor<Integer> RITUAL_TICKS = SynchedEntityData.defineId(RotatingSnowBlockEntity.class, 
            EntityDataSerializers.INT);
    
    private BlockPos centerPos;
    private BlockPos originalPos;
    private float currentRotation = 0.0F;
    private int maxRitualTicks = 120;
    private int transformTicks = 40;
    private boolean ritualCompleted = false;
    private int blockIndex;
    
    public RotatingSnowBlockEntity(EntityType<?> entityType, Level level) {
        super(entityType, level);
        this.noPhysics = true;
    }
    
    public RotatingSnowBlockEntity(EntityType<?> entityType, Level level, BlockPos centerPos, BlockPos originalPos, int blockIndex) {
        this(entityType, level);
        this.centerPos = centerPos;
        this.originalPos = originalPos;
        this.blockIndex = blockIndex;
        setPos(originalPos.getX() + 0.5, originalPos.getY() + 0.5, originalPos.getZ() + 0.5);
    }
    
    @Override
    protected void defineSynchedData() {
        entityData.define(ROTATION_SPEED, 2.0F);
        entityData.define(RITUAL_TICKS, 0);
    }
    
    @Override
    public void tick() {
        super.tick();
        
        if (centerPos == null || originalPos == null) {
            return;
        }
        
        int currentTicks = entityData.get(RITUAL_TICKS);
        currentTicks++;
        entityData.set(RITUAL_TICKS, currentTicks);
        
        if (!ritualCompleted && currentTicks >= maxRitualTicks) {
            ritualCompleted = true;
        }
        
        if (!ritualCompleted) {
            performRitualMovement(currentTicks);
        } else {
            performTransformMovement(currentTicks - maxRitualTicks);
        }
    }
    
    private void performRitualMovement(int currentTicks) {
        float progress = (float) currentTicks / maxRitualTicks;
        float rotationSpeed = 2.0F + progress * 15.0F;
        entityData.set(ROTATION_SPEED, rotationSpeed);

        currentRotation += rotationSpeed;
        if (currentRotation >= 360.0F) {
            currentRotation -= 360.0F;
        }

        double radius = getRotationRadius();
        double angleOffset = getAngleOffset();
        
        double angle = Math.toRadians(currentRotation + angleOffset);
        double x = centerPos.getX() + 0.5 + Math.cos(angle) * radius;
        double z = centerPos.getZ() + 0.5 + Math.sin(angle) * radius;

        double y;
        if (progress < 0.7F) {
            y = originalPos.getY() + 0.5 + (progress / 0.7F) * 2.0F;
        } else {
            float fallProgress = (progress - 0.7F) / 0.3F;
            y = originalPos.getY() + 0.5 + 2.0F * (1.0F - fallProgress);
        }
        
        setPos(x, y, z);
    }
    
    private void performTransformMovement(int transformTicks) {
        float transformProgress = (float) transformTicks / this.transformTicks;

        double targetX = centerPos.getX() + 0.5;
        double targetZ = centerPos.getZ() + 0.5;
        double targetY = centerPos.getY() + 1.0;
        
        double currentX = getX();
        double currentZ = getZ();
        double currentY = getY();

        double newX = currentX + (targetX - currentX) * 0.15;
        double newZ = currentZ + (targetZ - currentZ) * 0.15;
        double newY = currentY + (targetY - currentY) * 0.1;
        
        setPos(newX, newY, newZ);

        float rotationSpeed = Math.max(1.0F, 17.0F * (1.0F - transformProgress));
        currentRotation += rotationSpeed;
        if (currentRotation >= 360.0F) {
            currentRotation -= 360.0F;
        }

        if (transformTicks == this.transformTicks) {
            discard();
        }
    }
    
    private double getRotationRadius() {
        return switch (blockIndex) {
            case 0 -> 0.3;
            case 1 -> 0.5;
            case 2, 3 -> 1.2;
            default -> 0.8;
        };
    }
    
    private double getAngleOffset() {
        return switch (blockIndex) {
            case 0 -> 0;
            case 1 -> 180;
            case 2 -> 90;
            case 3 -> 270;
            default -> 0;
        };
    }
    
    public float getRotationSpeed() {
        return entityData.get(ROTATION_SPEED);
    }
    
    public int getRitualTicks() {
        return entityData.get(RITUAL_TICKS);
    }
    
    public float getCurrentRotation() {
        return currentRotation;
    }
    
    @Override
    protected void readAdditionalSaveData(CompoundTag tag) {
        if (tag.contains("CenterX")) {
            centerPos = new BlockPos(tag.getInt("CenterX"), tag.getInt("CenterY"), tag.getInt("CenterZ"));
            originalPos = new BlockPos(tag.getInt("OriginalX"), tag.getInt("OriginalY"), tag.getInt("OriginalZ"));
            currentRotation = tag.getFloat("CurrentRotation");
            maxRitualTicks = tag.getInt("MaxRitualTicks");
            transformTicks = tag.getInt("TransformTicks");
            blockIndex = tag.getInt("BlockIndex");
            ritualCompleted = tag.getBoolean("RitualCompleted");
        }
    }
    
    @Override
    protected void addAdditionalSaveData(CompoundTag tag) {
        if (centerPos != null && originalPos != null) {
            tag.putInt("CenterX", centerPos.getX());
            tag.putInt("CenterY", centerPos.getY());
            tag.putInt("CenterZ", centerPos.getZ());
            tag.putInt("OriginalX", originalPos.getX());
            tag.putInt("OriginalY", originalPos.getY());
            tag.putInt("OriginalZ", originalPos.getZ());
            tag.putFloat("CurrentRotation", currentRotation);
            tag.putInt("MaxRitualTicks", maxRitualTicks);
            tag.putInt("TransformTicks", transformTicks);
            tag.putInt("BlockIndex", blockIndex);
            tag.putBoolean("RitualCompleted", ritualCompleted);
        }
    }
}